package org.example.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import lombok.extern.slf4j.Slf4j;
import org.example.mapper.PermissionMapper;
import org.example.mapper.RoleMapper;
import org.example.mapper.UserMapper;
import org.example.model.table.Menu;
import org.example.model.table.Permission;
import org.example.model.table.Role;
import org.example.model.table.User;
import org.example.model.vo.RoleVo;
import org.example.model.vo.UserVo;
import org.example.service.RoleService;
import org.example.util.JwtUtils;
import org.example.util.PageUtil;
import org.example.util.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;


@Slf4j
@Service
@Transactional(propagation = Propagation.REQUIRED)
public class RoleServiceImpl implements RoleService {
    // 默认角色Id
    private Long DEFAULT_ROLE = -1L;
    @Autowired
    RoleMapper roleMapper;
    @Autowired
    UserMapper userMapper;
    @Autowired
    PermissionMapper permissionMapper;

    @Override
    public Result addRole(String token, RoleVo roleVo) {
        UserVo userInfo = JwtUtils.toObj(token, UserVo.class);
        LambdaQueryWrapper<User> userQueryWrapper = new LambdaQueryWrapper<>();
        userQueryWrapper.eq(User::getAccount, userInfo.getAccount());
        // 判断token封装的account是否存在
        User tokenUser = userMapper.selectOne(userQueryWrapper);
        if (tokenUser.getAccount() != null) {
            // 查询数据库是否已有角色,role字段和name字段具有唯一约束
            LambdaQueryWrapper<Role> roleQueryWrapper = new LambdaQueryWrapper<>();
            roleQueryWrapper.eq(Role::getRole, roleVo.getRole()).eq(Role::getName, roleVo.getName());
            if (roleMapper.selectOne(roleQueryWrapper) != null) {
                return Result.error()
                        .data("msg", "Role already exists");
            }
            Role role = new Role();
            role.setRole(roleVo.getRole());
            role.setName(roleVo.getName());
            role.setStatus(roleVo.getStatus());
            roleMapper.insert(role);
            List<Permission> permissionList = new ArrayList<>();
            List<Menu> menus = roleVo.getMenus();
            if (menus.size() > 0) {
                menus.forEach(menu -> {
                    Permission permission = new Permission();
                    permission.setRoleId(role.getId());
                    permission.setMenuId(menu.getId());
                    permissionList.add(permission);
                });
            }

            permissionList.forEach(permission -> {
                permissionMapper.insert(permission);
            });
            return Result.ok()
                    .data("msg", "add role Success");
        }
        return Result.error()
                .data("msg", "add role fail");
    }

    @Override
    public Result editRole(String token, RoleVo roleVo) {
        UserVo userInfo = JwtUtils.toObj(token, UserVo.class);
        if ((roleVo.getId() == null)) {
            return Result.error()
                    .data("msg", "edit Role fail, missing required parameter `id`");
        }
        if ((roleVo.getId() == -1)) {
            return Result.error()
                    .data("msg", "edit Role fail, admin is not allowed to be modified");
        }
        List<Permission> permissionList = new ArrayList<>();
        List<Menu> menus = roleVo.getMenus();
        if (menus.size() > 0) {
            menus.forEach(menu -> {
                Permission permission = new Permission();
                permission.setRoleId(roleVo.getId());
                permission.setMenuId(menu.getId());
                log.info(permission.toString());
                permissionList.add(permission);
            });
        }
        LambdaQueryWrapper<Permission> permissionQueryWrapper = new LambdaQueryWrapper<>();
        permissionQueryWrapper.eq(Permission::getRoleId, roleVo.getId());
        permissionMapper.delete(permissionQueryWrapper);

        permissionList.forEach(permission -> {
            permissionMapper.insert(permission);
        });
        LambdaUpdateWrapper<Role> roleUpdateWrapper = new LambdaUpdateWrapper<>();
        roleUpdateWrapper.set(StringUtils.isNotBlank(roleVo.getRole()), Role::getRole, roleVo.getRole())
                .set(StringUtils.isNotBlank(roleVo.getName()), Role::getName, roleVo.getName())
                .set(roleVo.getStatus() != null, Role::getStatus, roleVo.getStatus())
                .eq(Role::getId, roleVo.getId());
        roleMapper.update(null, roleUpdateWrapper);
        return Result.ok()
                .data("msg", "edit Role Success");
    }

    @Override
    public Result getPageRole(int page, int size, RoleVo roleVo) {
        MPJLambdaWrapper<Role> wrapper = new MPJLambdaWrapper<>();
        wrapper
                .selectAs(Role::getId, RoleVo::getId)
                .selectAs(Role::getRole, RoleVo::getRole)
                .selectAs(Role::getName, RoleVo::getName)
                .selectAs(Role::getStatus, RoleVo::getStatus)
                .eq(roleVo.getId() != null, Role::getId, roleVo.getId())
                .eq(roleVo.getStatus() != null, Role::getStatus, roleVo.getStatus())
                .eq(StringUtils.isNotBlank(roleVo.getRole()), Role::getRole, roleVo.getRole())
                .eq(StringUtils.isNotBlank(roleVo.getName()), Role::getName, roleVo.getName());
        IPage<RoleVo> roleVoIPage = roleMapper.selectJoinPage(new Page<>(page, size), RoleVo.class, wrapper);
        if (roleVoIPage != null && roleVoIPage.getRecords().size() > 0) {
            return Result.ok().data("roleList", roleVoIPage);
        }

        return Result.ok().data("msg", "暂无数据").setCode(404);
    }

    /**
     * 这是一对多查询，故无法使用传统·1分页插件，需在查询完成后操作，
     * `多`数据被分发到转换模型的一个列表中
     */
    @Override
    public Result getRoleAndMenu(Integer page, Integer size, RoleVo roleVo) {
        /*
        select * from role t
            inner join permission t1 on t.id = t1.role_id
            inner join menu t2 on t1.menu_id = t2.id
        where t.id=1;
         */
        MPJLambdaWrapper<Role> wrapper = new MPJLambdaWrapper<>();
        wrapper
                .selectAs(Role::getId, RoleVo::getId)
                .selectAs(Role::getRole, RoleVo::getRole)
                .selectAs(Role::getName, RoleVo::getName)
                .selectAs(Role::getStatus, RoleVo::getStatus)
                .selectCollection(Menu.class, RoleVo::getMenus)
                .innerJoin(Permission.class, Permission::getRoleId, Role::getId)
                .innerJoin(Menu.class, Menu::getId, Permission::getMenuId)
                .eq(roleVo.getStatus() != null, Role::getStatus, roleVo.getStatus())
                .like(StringUtils.isNotBlank(roleVo.getRole()), Role::getRole, roleVo.getRole());
        List<RoleVo> roleVos = roleMapper.selectJoinList(RoleVo.class, wrapper);
        if (roleVos != null && roleVos.size() > 0) {
            Map<String, Object> listPage = PageUtil.ListPage(page, size, roleVos);
            return Result.ok().data("roleList", listPage);
        }
        return Result.ok().data("msg", "暂无数据").setCode(404);
    }

    @Override
    public Result deleteById(Long id) {
        // 删除角色，应当将该角色下的所有用户移至默认分组
        LambdaUpdateWrapper<User> userUpdateWrapper = new LambdaUpdateWrapper<>();
        userUpdateWrapper.set(User::getRoleId, DEFAULT_ROLE).eq(User::getRoleId, id);
        userMapper.update(null, userUpdateWrapper);

        int i = roleMapper.deleteById(id);
        return i == 1 ?
                Result.ok().data("msg", "成功删除") :
                Result.error().data("msg", "删除失败").setCode(501);

    }

    @Override
    public Result switchStatusById(Long id, Long status) {
        LambdaUpdateWrapper<Role> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(Role::getStatus, status).eq(Role::getId, id);
        int i = roleMapper.update(null, updateWrapper);
        return i == 1 ?
                Result.ok().data("msg", "修改成功") :
                Result.error().data("msg", "修改失败").setCode(501);
    }

    @Override
    public Result getRoleCount() {
        Long count = roleMapper.selectCount(null);
        return Result.ok().data("count", count);
    }
}
